package com.superquan.selfstudybootmybatis.utils.circulardependency;

import lombok.SneakyThrows;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zwq
 * @description 解决循环依赖测试类
 * @date 2022/3/29
 * Spring内部维护了三个Map，也就是我们通常说的三级缓存
 * singletonObjects 它是我们最熟悉的朋友，俗称“单例池”“容器”，缓存创建完成单例Bean的地方。
 * singletonFactories 映射创建Bean的原始工厂
 * earlySingletonObjects 映射Bean的早期引用，也就是说在这个Map里的Bean不是完整的，甚至还不能称之为“Bean”，只是一个Instance.
 * 参考：https://juejin.cn/post/6844904122160775176#comment
 */
public class CirDependTest {

    private static Map<String,Object> cacheMap=new HashMap<>(2);
    
    @SneakyThrows
    public static <T> T getBean(Class<T> beanClass){
        //本文用类名小写 简单代替dbeane 命名规则
        String beanName = beanClass.getSimpleName().toLowerCase();
        //如果已经是一个bean 则直接返回
        if(cacheMap.containsKey(beanName)){
            return (T)cacheMap.get(beanName);
        }
        //将对象本身实例化
        Object object = beanClass.getDeclaredConstructor().newInstance();
        //放入缓存
        cacheMap.put(beanName,object);
        //把所有字段当成需要注入的bean，创建并注入到当前bean中
        Field[] fields = object.getClass().getDeclaredFields();
        for(Field field:fields){
            field.setAccessible(true);
            //获取需要注入的class
            Class<?> fieldClass = field.getType();
            String fieldBeanName = fieldClass.getSimpleName().toLowerCase();
            //如果需要注入的bean已经在缓存map中，那么把缓存map的值注入到该field即可
            //如果缓存没有 则继续创建
            field.set(object,cacheMap.containsKey(fieldBeanName)?cacheMap.get(fieldBeanName):getBean(fieldClass));
        }
        //属性填充完成 返回
        return (T)object;
    }

    public static void main(String[] args) {
        //假装扫描出来的对象
        Class[] classes={SuperA.class,SuperB.class};
        //假装项目初始化实例化所有bean
        for(Class aClass:classes){
            getBean(aClass);
        }
//        System.out.println(getBean(SuperB.class).getSuperA()==getBean(SuperA.class));
//        System.out.println(getBean(SuperA.class).getSuperB()==getBean(SuperB.class));
    }
}
